package com.lechi.iot.netty.message;


import com.lechi.iot.netty.data.TcpByteArrayData;
import com.lechi.iot.netty.data.TcpData;
import com.lechi.iot.netty.utils.Hex;
import com.lechi.iot.netty.utils.IntegerToByteUtil;
import com.lechi.iot.netty.utils.ModbusCrc16Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;

/**
 * 对接收到的指令数据进行校验
 */
@Slf4j
public class TcpInMessage implements TcpMessage {

    private final String deviceGroup;
    /**
     * 报文功能码
     */
    private final int adviceAddr;
    private String deviceSn;
    /**
     * 报文
     */
    private byte[] msg;
    /**
     * 报文长度
     */
    private int length;
    private TcpData data;

    public TcpInMessage(String channelName, String deviceSn) {
        this.deviceGroup = channelName;
        this.deviceSn = deviceSn;
        this.adviceAddr = REGISTERED_INDEX;
    }


    public TcpInMessage(String channelName, byte[] msg) {
        this.deviceGroup = channelName;
        this.msg = msg;
        byte[] dataArr = new byte[0];
        byte[] dataLength = new byte[0];
        try {
            dataArr = ArrayUtils.subarray(msg, DATA_BEGIN_INDEX, msg.length - 2);
            dataLength = ArrayUtils.subarray(msg, DATA_BEGIN_INDEX - 1, DATA_BEGIN_INDEX);
        } catch (Exception e) {
            log.error("站点地址：{} 报文数组越界异常{} !", channelName, Hex.toHexString(msg));
            throw new RuntimeException("数组越界异常{}");
        }
        if (dataArr.length != IntegerToByteUtil.bytesToInt(dataLength)) {
            log.error("站点地址：{} 报文描述的长短和数据本身长度不一致{} !", channelName, Hex.toHexString(msg));
            throw new RuntimeException("报文描述的长短和数据本身长度不一致");
        }
        byte[] checkCode = {msg[msg.length - 2], msg[msg.length - 1]};
        byte[] checkData = ArrayUtils.subarray(msg, BEGIN_INDEX, msg.length - 2);
        if (!ModbusCrc16Utils.getCrcString(checkData).equals(Hex.toHexString(checkCode))) {
            log.error("站点地址：{} ,报文校验码校验错误: {} !", channelName,  Hex.toHexString(msg));
            throw new RuntimeException("报文校验码校验错误");
        }
        this.length = msg.length;
        this.adviceAddr = msg[0];
        this.data = new TcpByteArrayData(dataArr);
    }

    public String deviceGroup() {
        return deviceGroup;
    }

    public String deviceSn() {
        return deviceSn;
    }

    public int adviceAddr() {
        return adviceAddr;
    }


    public int length() {
        return length;
    }

    public TcpData data() {
        return data;
    }

    public int type() {
        return RECV;
    }

    public byte[] toBytes() {
        return msg;
    }
}
